package com.smedi.ismedi.constructionproject.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.constructionproject.core.application.query.ProjectAssignmentQueryService;
import com.smedi.ismedi.constructionproject.core.application.query.ProjectBasicQueryService;
import com.smedi.ismedi.constructionproject.core.application.query.vo.ProjectBasicVo;
import com.smedi.ismedi.constructionproject.core.domain.aggregatemodel.*;
import com.smedi.ismedi.constructionproject.core.domain.dto.FileQuery;
import com.smedi.ismedi.constructionproject.core.domain.repository.FileRepository;
import com.smedi.ismedi.constructionproject.core.domain.repository.PersonBasicRepository;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectApplyRepository;
import com.smedi.ismedi.constructionproject.core.domain.repository.ProjectBasicRepository;
import com.smedi.ismedi.constructionproject.core.infrastructure.enumerate.MonitorTypeEnum;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.model.ProjectApplyAttachmentRelationshipEntity;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.model.ProjectApplyEntity;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.mybatis.mapper.ProjectApplyAttachmentRelationshipMapper;
import com.smedi.ismedi.constructionproject.core.port.adapter.persistence.mybatis.mapper.ProjectApplyMapper;
import com.smedi.ismedi.constructionproject.core.port.adapter.restful.convert.AdapterConverter;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.constructionproject.core.port.adapter.service.PersonnelRemoteApiService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: xulinjun
 * @Date: 2021-6-18 15:55
 */
@Slf4j
@Repository
@AllArgsConstructor
@Transactional
public class ProjectApplyRepositoryImpl implements ProjectApplyRepository {
    private final AdapterConverter adapterConverter;

    private final ProjectApplyMapper projectApplyMapper;

    private final ProjectApplyAttachmentRelationshipMapper projectApplyAttachmentRelationshipMapper;

    private final ProjectBasicRepository projectBasicRepository;

    private final PersonBasicRepository personBasicRepository;

    private final FileRepository fileRepository;

    private final AuthorityUtil authorityUtil;

    private final PersonnelRemoteApiService personnelRemoteApiService;

    private final ProjectAssignmentQueryService projectAssignmentQueryService;

    private final OrganizationRemoteApiService organizationRemoteApiService;

    private final ProjectBasicQueryService projectBasicQueryService;


    @Override
    public ProjectApply saveProjectApply(ProjectApply projectApply) {
        ProjectApplyEntity projectApplyEntity = adapterConverter.projectApplyToEntity(projectApply);
        projectApplyEntity.setCurrentDealPersonId(authorityUtil.getPersonId());
        projectApplyEntity.setLastedDealTime(LocalDateTime.now());

        if (ObjectUtils.isNull(projectApplyEntity.getId())) {
            projectApplyEntity.setApplyPersonId(authorityUtil.getPersonId());
            projectApplyEntity.setApplyTime(LocalDateTime.now());
            projectApplyMapper.insert(projectApplyEntity);
        }
        if (ObjectUtils.isNotNull(projectApplyEntity.getId())) {
            LambdaQueryWrapper<ProjectApplyAttachmentRelationshipEntity> projectApplyAttachmentQueryWrapper = new LambdaQueryWrapper<>();
            projectApplyAttachmentQueryWrapper.eq(ProjectApplyAttachmentRelationshipEntity::getProjectApplyId, projectApplyEntity.getId());
            projectApplyAttachmentRelationshipMapper.delete(projectApplyAttachmentQueryWrapper);

            projectApplyMapper.updateById(projectApplyEntity);
        }

        //更新附件表
        for (File attachment : projectApply.getFiles()) {
            projectApplyAttachmentRelationshipMapper.insert(ProjectApplyAttachmentRelationshipEntity.builder()
                    .projectApplyId(projectApplyEntity.getId())
                    .attachment(attachment.getSignKey())
                    .build());
        }
        return this.extend(projectApplyEntity);
    }

    @Override
    public void deleteProjectApply(ProjectApply projectApply) {
        ProjectApplyEntity projectApplyEntity = adapterConverter.projectApplyToEntity(projectApply);
        projectApplyEntity.setDeleted(true);
        projectApplyMapper.updateById(projectApplyEntity);
    }

    @Override
    public ProjectApply getProjectApplyOne(ProjectApplyQuery projectApplyQuery) {
        LambdaQueryWrapper<ProjectApplyEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        //通过id查找
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getId()), ProjectApplyEntity::getId, projectApplyQuery.getId());
        ProjectApplyEntity projectApplyEntity = projectApplyMapper.selectOne(lambdaQueryWrapper);

        return this.extend(projectApplyEntity);
    }

    @Override
    public List<ProjectApply> getProjectApplyList(ProjectApplyQuery projectApplyQuery) {
        LambdaQueryWrapper<ProjectApplyEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        //通过id查找
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getId()), ProjectApplyEntity::getId, projectApplyQuery.getId());
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getApplyType()), ProjectApplyEntity::getApplyType, projectApplyQuery.getApplyType());
        //通过projectId查找
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getProjectId()), ProjectApplyEntity::getProjectId, projectApplyQuery.getProjectId());

        lambdaQueryWrapper.orderBy(true, false, ProjectApplyEntity::getLastedDealTime);

        List<ProjectApplyEntity> projectApplyEntityList = projectApplyMapper.selectList(lambdaQueryWrapper);

        return this.extend(projectApplyEntityList);
    }

    @Override
    public Page<ProjectApply> getProjectApplyPage(ProjectApplyQuery projectApplyQuery) {
        Page<ProjectApplyEntity> projectApplyEntityPage = new Page<>(projectApplyQuery.getCurrent(), projectApplyQuery.getSize());

        LambdaQueryWrapper<ProjectApplyEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        //申报人查询
        if (StringUtils.isNotBlank(projectApplyQuery.getApplyPersonName())) {
            List<Long> personIds = personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndEmployeeNumAndMobile(projectApplyQuery.getApplyPersonName(), null, null, null);
            if (CollectionUtils.isEmpty(personIds)) {
                return new Page<>(projectApplyQuery.getCurrent(), projectApplyQuery.getSize());
            }
            lambdaQueryWrapper.in(ProjectApplyEntity::getApplyPersonId, personIds);
        }
        //项目id查询
        if (ObjectUtils.isNotEmpty(projectApplyQuery.getProjectId())) {
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getProjectId()), ProjectApplyEntity::getProjectId, projectApplyQuery.getProjectId());
        } else {
            List<Long> projectIds = getProjectIds(projectApplyQuery.getHrOrganizationId());
            lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectIds), ProjectApplyEntity::getProjectId, projectIds);
        }
        //申报时间查询
        if (ObjectUtils.isNotNull(projectApplyQuery.getApplyStartTime()) && ObjectUtils.isNotNull(projectApplyQuery.getApplyEndTime())) {
            lambdaQueryWrapper.between(ProjectApplyEntity::getApplyTime, projectApplyQuery.getApplyStartTime(), projectApplyQuery.getApplyEndTime());
        }
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getApplyType()), ProjectApplyEntity::getApplyType, projectApplyQuery.getApplyType());
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(projectApplyQuery.getApplyStatus()), ProjectApplyEntity::getApplyStatus, projectApplyQuery.getApplyStatus());

        lambdaQueryWrapper.orderBy(true, false, ProjectApplyEntity::getLastedDealTime);

        Page<ProjectApplyEntity> projectApplyEntityPage1 = projectApplyMapper.selectPage(projectApplyEntityPage, lambdaQueryWrapper);
        Page<ProjectApply> projectApplyPage = adapterConverter.entityPageToPage(projectApplyEntityPage1);

        projectApplyPage.setRecords(this.extend(projectApplyEntityPage1.getRecords()));

        return projectApplyPage;
    }

    @Override
    public Boolean restoreProject(Long projectId) {
        ProjectBasic projectBasic = projectBasicRepository.selectByProjectId(projectId);
        projectBasic.setMonitorType(MonitorTypeEnum.DEFAULT_TYPE.getValue());
        projectBasicRepository.doUpdate(projectBasic);
        return true;
    }

    private ProjectApply extend(ProjectApplyEntity projectApplyEntity) {
        if (projectApplyEntity == null) {
            return null;
        }

        List<ProjectApplyEntity> projectApplyEntityList = new ArrayList<>();
        projectApplyEntityList.add(projectApplyEntity);
        List<ProjectApply> ProjectApplyList = this.extend(projectApplyEntityList);

        return ProjectApplyList.get(0);
    }

    private List<ProjectApply> extend(List<ProjectApplyEntity> projectApplyEntityList) {
        if (projectApplyEntityList.isEmpty()) {
            return new ArrayList<>();
        }

        List<ProjectApply> projectApplyList = new ArrayList<>();

        Set<Long> projectIds = new HashSet<>();
        Set<Long> projectApplyIds = new HashSet<>();
        Set<Long> personIds = new HashSet<>();
        Set<String> attachmentKeys = new HashSet<>();

        Map<String, File> attachmentMap = new HashMap<>();
        Map<Long, Person> idPersonMap = new HashMap<>();

        for (ProjectApplyEntity projectApplyEntity : projectApplyEntityList) {
            Long projectId = projectApplyEntity.getProjectId();
            if (projectId != null) {
                projectIds.add(projectId);
            }
            projectApplyIds.add(projectApplyEntity.getId());
            personIds.add(projectApplyEntity.getApplyPersonId());
            personIds.add(projectApplyEntity.getCurrentDealPersonId());
        }

        //通过附表实体类的项目申请id，查找附表key
        LambdaQueryWrapper<ProjectApplyAttachmentRelationshipEntity> projectApplyAttachmentQueryWrapper = new LambdaQueryWrapper<>();
        projectApplyAttachmentQueryWrapper.in(ProjectApplyAttachmentRelationshipEntity::getProjectApplyId, projectApplyIds);
        List<ProjectApplyAttachmentRelationshipEntity> projectApplyAttachmentRelationshipEntityEntities = projectApplyAttachmentRelationshipMapper.selectList(projectApplyAttachmentQueryWrapper);
        Map<Long, List<String>> projectApplyAttachmentKeysMap = new HashMap<>();
        for (ProjectApplyAttachmentRelationshipEntity entity : projectApplyAttachmentRelationshipEntityEntities) {
            List<String> attachmentKeysByApplyId = projectApplyAttachmentKeysMap.getOrDefault(entity.getProjectApplyId(), new ArrayList<>());
            attachmentKeysByApplyId.add(entity.getAttachment());
            //HashMap中存储eqpId与attachmentKeys
            projectApplyAttachmentKeysMap.put(entity.getProjectApplyId(), attachmentKeysByApplyId);
            attachmentKeys.add(entity.getAttachment());
        }

        List<ProjectBasic> projects = projectBasicRepository.selectByProjectIds(new ArrayList<>(projectIds));
        Map<Long, ProjectBasic> idProjectMap = new HashMap<>();
        for (ProjectBasic project : projects) {
            idProjectMap.put(project.getProjectId(), project);
        }
        if (CollectionUtils.isNotEmpty(personIds)) {
            List<Person> persons = personBasicRepository.selectByPersonIds(new ArrayList<>(personIds));

            for (Person idPerson : persons) {
                idPersonMap.put(idPerson.getId(), idPerson);
            }
        }
        if (CollectionUtils.isNotEmpty(attachmentKeys)) {
            List<File> files = fileRepository.getFileList(FileQuery.builder().signKeys(new ArrayList<>(attachmentKeys)).build());

            for (File attachment : files) {
                attachmentMap.put(attachment.getSignKey(), attachment);
            }
        }

        for (ProjectApplyEntity projectApplyEntity : projectApplyEntityList) {
            ProjectApply projectApply = adapterConverter.projectApplyEntityToProjectApply(projectApplyEntity);

            projectApply.setProject(idProjectMap.get(projectApplyEntity.getProjectId()));
            projectApply.setApplyPerson(idPersonMap.getOrDefault(projectApplyEntity.getApplyPersonId(), new Person(projectApplyEntity.getApplyPersonId())));
            projectApply.setCurrentDealPerson(idPersonMap.getOrDefault(projectApplyEntity.getCurrentDealPersonId(), new Person(projectApplyEntity.getCurrentDealPersonId())));

            List<File> attachments = new ArrayList<>();
            List<String> equipmentAttachmentKeys = projectApplyAttachmentKeysMap.getOrDefault(projectApplyEntity.getId(), new ArrayList<>());
            for (String key : equipmentAttachmentKeys) {
                attachments.add(attachmentMap.getOrDefault(key, new File(key)));
            }
            projectApply.setFiles(attachments);

            projectApplyList.add(projectApply);
        }

        return projectApplyList;
    }

    public List<Long> getProjectIds(Long hrOrganizationId) {
        Set<Long> projectIdSet = new HashSet<>();
        if (null != hrOrganizationId) {
            List<Long> hrOrganizationIds = organizationRemoteApiService.getHrOrganizationChildrenOrgIdList(hrOrganizationId);
            List<ProjectBasicVo> projectBasicVos = projectBasicQueryService.getProjectBasicListByHrOrganizationIds(hrOrganizationIds);
            if (CollectionUtils.isNotEmpty(projectBasicVos)) {
                projectIdSet.addAll(projectBasicVos.stream().map(ProjectBasicVo::getProjectId).collect(Collectors.toList()));
            }
        }
        List<Long> projectIdsByPersonId = projectAssignmentQueryService.getDistinctProjectIdsByPersonId(authorityUtil.getPersonId());
        projectIdSet.addAll(projectIdsByPersonId);

        return new ArrayList<>(projectIdSet);
    }
}